﻿using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.Intrinsics.Arm;
using System.Threading.Tasks;
using Entity.Models;
using HuaRunInterface.Comm;
using HuaRunInterface.Models;
using HuaRunLanYanInterface.Controllers;
using HuaRunLanYanInterface.Controllers.RollbackControllers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Ocsp;
using Utility;
using static NPOI.HSSF.Util.HSSFColor;

/// <summary>
/// 推送实时数据
/// </summary>
namespace HuaRunLanYanInterface.Controllers
{
    public delegate void RtuUpdateBalance(ReqRtuRemainMoneyModel model);

    [Route("api/Data/MeterData/Add")]
    [ApiController]
    public class MeterDataAddController : ControllerBase
    {
        // GET: api/MeterDataAdd
        [HttpGet]
        public ContentResult Get(object value)
        {
            return TS_MeterData(value);
        }

        // POST: api/MeterDataAdd
        [HttpPost]
        public ContentResult Post([FromBody] object value)
        {
            return TS_MeterData(value);
        }

        private ContentResult TS_MeterData(object obj)
        {
            ResBaseModel2 res = new ResBaseModel2();
            try
            {
                MeterDataModel req = obj.ToString().JSONStringToObject<MeterDataModel>();
                WriteLog.WriteRealLogsFile("meter data add value: " + req.SerializerObjectToString());
                string conn = Global.Configuration["ConnectionStrings:DDb"];
                using (Entity.DBContext context = Entity.BaseContext.CreateContext(conn))
                {
                    RTUInfo? rm = context.rTUInfos.Where(p => p.deviceCode == req.meter_comm_no && p.IsDelete != 1).FirstOrDefault();
                    if (rm == null)
                    {
                        res.State = "success";
                        res.Message = "没有当前设备";
                        res.Data = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
                        return Content(JsonConvert.SerializeObject(res));
                    }

                    MeterData_ExtModel ext = req.ext_data.JSONStringToObject<MeterData_ExtModel>();
                    #region define
                    //RealDataInfo real = context.realDataInfos.Where(p => p.deviceCode == req.meter_comm_no).OrderByDescending(p => p.CreateDate).FirstOrDefault();
                    //if (real == null)
                    //{
                    //    real = new RealDataInfo();
                    //    real.deviceCode = req.meter_comm_no;
                    //    real.StdSum = req.std_sum;
                    //    real.Price = req.curr_price;
                    //    real.RemainMoney = req.remain_money;
                    //    real.ValveState = (bool)ext.valve_open ? 0 : 1;
                    //    real.CreateDate = DateTime.Now;
                    //    context.realDataInfos.Add(real);
                    //}
                    //else
                    //{
                    //    real.StdSum = req.std_sum;
                    //    real.Price = req.curr_price;
                    //    real.RemainMoney = req.remain_money;
                    //    real.ValveState = (bool)ext.valve_open ? 0 : 1;
                    //    context.realDataInfos.Update(real);
                    //}
                    //context.SaveChanges();
                    #endregion
                    string apiAddress = "eciot-openapi/industry/meter/read";
                    RtuDataUpModel rData = new RtuDataUpModel();
                    rData.transaction = Guid.NewGuid().ToString();
                    rData.body = new List<RtuReadingDetails>();
                    RtuReadingDetails body = new RtuReadingDetails();
                    body.sequence = "Read" + DateTime.Now.ToString("yyMMddHHmmssff");
                    body.domainId = Global.DomainId;
                    body.deviceCode = rm.deviceCode;
                    body.deviceType = rm.deviceType;
                    body.uniqueDeviceIdentifier = rm.uniqueDeviceIdentifier;
                    body.standardNum = (double)req.std_sum;
                    body.workNum = (double)req.work_sum;
                    body.instantStandardNum = (double)req.std_flow;
                    body.instantWorkNum = (double)req.work_flow;
                    body.temperature = (double)req.temperature;
                    body.pressure = (double)req.pressure;
                    body.meterFactoryCode = Global.Configuration["AppSettings:FactoryCode"];
                    body.valveStatus = ext.valve_open.Value ? 0 : 1;
                    body.signalQuality = req.rssi;
                    body.readTime = req.acquisition_time;
                    body.warnInfos = GetAlarmInfo(req.meter_state, req.acquisition_time);
                    rData.body.Add(body);
                    string errMsg = "";
                    bool result = Global.CommonSend(apiAddress, rData, ref errMsg);
                    WriteLog.WriteRealLogsFile($"MeterDataAdd rtu data upload : {result};msg:{errMsg}");
                    if (result)
                    {
                        res.State = "success";
                        res.Message = "成功";
                        res.Data = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
                    }
                    else
                    {
                        res.Data = errMsg;
                    }
                    //SendAlarmInfo(req, rm);
                }
            }
            catch (Exception ex)
            {
                WriteLog.WriteExceptionFile("meter data add : " + ex.Message + "\r\n" + ex.StackTrace);
            }
            string str = JsonConvert.SerializeObject(res);
            WriteLog.WriteRealLogsFile("meter data add return to platform : " + str);
            return Content(str);
        }

        private void SendAlarmInfo(MeterDataModel value, RTUInfo rtu)
        {
            try
            {
                string apiInterface = "eciot-openapi/meter/warnInfos";

                SendAlarmModel data = new SendAlarmModel();
                data.sequence = "Alarm" + DateTime.Now.ToString("yyMMddHHmmssff");
                data.domainId = Global.DomainId;
                data.deviceType = rtu.deviceType;
                data.protocolTypeCode = rtu.protocolTypeCode;
                data.uniqueDeviceIdentifier = rtu.uniqueDeviceIdentifier;
                data.deviceCode = rtu.deviceCode;
                data.warnInfos = new List<AlarmInfo>();
                if (value.meter_state != 0)
                {
                    //if (((value.meter_state >> 15) & 1) == 1)
                    {
                        AlarmInfo a = new AlarmInfo();
                        a.warnTime = value.acquisition_time;
                        a.warnCode = 17;
                        a.warnDesc = "阀门异常：强行关阀";
                        data.warnInfos.Add(a);
                    }
                    // if (((value.meter_state >> 14) & 1) == 1)
                    {
                        AlarmInfo b = new AlarmInfo();
                        b.warnTime = value.acquisition_time;
                        b.warnCode = 42;
                        b.warnDesc = "低电报警";
                        data.warnInfos.Add(b);
                    }
                    //if (((value.meter_state >> 12) & 1) == 1)
                    {
                        AlarmInfo c = new AlarmInfo();
                        c.warnTime = value.acquisition_time;
                        c.warnCode = 18;
                        c.warnDesc = "强磁干扰";
                        data.warnInfos.Add(c);
                    }
                    if (((value.meter_state >> 9) & 1) == 1)
                    {
                        AlarmInfo e = new AlarmInfo();
                        e.warnTime = value.acquisition_time;
                        e.warnCode = 37;
                        e.warnDesc = "过流报警:流量超过设定值";
                        data.warnInfos.Add(e);
                    }
                    if (((value.meter_state >> 8) & 1) == 1)
                    {
                        AlarmInfo d = new AlarmInfo();
                        d.warnTime = value.acquisition_time;
                        d.warnCode = 50;
                        d.warnDesc = "死表故障:用户长时间未用，表具自动关闭阀门";
                        data.warnInfos.Add(d);
                    }
                    if (((value.meter_state >> 0) & 1) == 1)
                    {
                        AlarmInfo f = new AlarmInfo();
                        f.warnTime = value.acquisition_time;
                        f.warnCode = 99;
                        f.warnDesc = "干簧管坏";
                        data.warnInfos.Add(f);
                    }
                }
                if (data.warnInfos.Count > 0)
                {
                    string err = "";
                    bool result = Global.CommonSend(apiInterface, data.SerializerObjectToString(), ref err);
                    WriteLog.WriteLogFile($"报警推送返回：{result},报警推送数据：{data.SerializerObjectToString()}");
                }
            }
            catch (Exception ex)
            {
                WriteLog.WriteExceptionFile("send alarm info : " + ex.Message + "\r\n" + ex.StackTrace);
            }
        }

        private List<RtuWarnInfoModel> GetAlarmInfo(int state, DateTime time)
        {
            List<RtuWarnInfoModel> data = new List<RtuWarnInfoModel>();
            if (state != 0)
            {
                if (((state >> 15) & 1) == 1)
                {
                    RtuWarnInfoModel a = new RtuWarnInfoModel();
                    a.warnTime = time;
                    a.warnCode = 17;
                    a.warnDesc = "阀门异常：强行关阀";
                    data.Add(a);
                }
                if (((state >> 14) & 1) == 1)
                {
                    RtuWarnInfoModel b = new RtuWarnInfoModel();
                    b.warnTime = time;
                    b.warnCode = 42;
                    b.warnDesc = "低电报警";
                    data.Add(b);
                }
                if (((state >> 12) & 1) == 1)
                {
                    RtuWarnInfoModel c = new RtuWarnInfoModel();
                    c.warnTime = time;
                    c.warnCode = 18;
                    c.warnDesc = "强磁干扰";
                    data.Add(c);
                }
                if (((state >> 9) & 1) == 1)
                {
                    RtuWarnInfoModel e = new RtuWarnInfoModel();
                    e.warnTime = time;
                    e.warnCode = 37;
                    e.warnDesc = "过流报警:流量超过设定值";
                    data.Add(e);
                }
                if (((state >> 8) & 1) == 1)
                {
                    RtuWarnInfoModel d = new RtuWarnInfoModel();
                    d.warnTime = time;
                    d.warnCode = 50;
                    d.warnDesc = "死表故障:用户长时间未用，表具自动关闭阀门";
                    data.Add(d);
                }
                if (((state >> 0) & 1) == 1)
                {
                    RtuWarnInfoModel f = new RtuWarnInfoModel();
                    f.warnTime = time;
                    f.warnCode = 99;
                    f.warnDesc = "干簧管坏";
                    data.Add(f);
                }
            }
            return data;
        }
    }

    public class MeterDataModel
    {
        public string meter_comm_no { get; set; }// nvarchar(50) 通信号，物联网表 14 位，无线表 10 位
        public int device_type { get; set; }//int 设备类型
        public string device_type_name { get; set; }//nvarchar(50) 设备类型名称
        public string factory_code { get; set; }//nvarchar(50) 厂家代码
        public string meter_area_no { get; set; }//nvarchar(50) 分区号
        public string meter_define_no1 { get; set; }//nvarchar(50) 用户自定义编号 1
        public string meter_define_no2 { get; set; }//nvarchar(50) 用户自定义编号 2
        public string meter_define_no3 { get; set; }//nvarchar(50) 用户自定义编号 3
        public string meter_define_no4 { get; set; }// nvarchar(50) 用户自定义编号 4
        public int data_type { get; set; }//Int 数据类型(0-实时数据 1-冻结数据)
        public string data_type_name { get; set; }//nvarchar(50) 数据类型名称
        public DateTime acquisition_time { get; set; }//Datetime 采集时间/冻结时间
        public DateTime receive_time { get; set; }//Datetime 数据接收时间
        public decimal std_sum { get; set; }//Decimal(18,3) 标况总累计量
        public decimal work_sum { get; set; }// Decimal(18,3) 工况总累计量
        public decimal std_flow { get; set; }// Decimal(18,3) 标况瞬时流量
        public decimal work_flow { get; set; }// Decimal(18,3) 工况瞬时流量
        public decimal temperature { get; set; }// Decimal(18,3) 温度
        public decimal pressure { get; set; }//Decimal(18,3) 压力
        public int magatt_times { get; set; }//Int 磁攻击次数
        public decimal this_month_sum { get; set; }// Decimal(18,3) 当月累计用量(来自表内)
        public decimal last_month_sum { get; set; }//Decimal(18,3) 上月累计用量(来自表内)
        public decimal this_cycle_sum { get; set; }//Decimal(18,3) 本周期累计用量(来自表内)
        public decimal last_cycle_sum { get; set; }// Decimal(18,3) 上周期累计用量(来自表内)
        public decimal remain_money { get; set; }// Decimal(18,3) 剩余金额
        public decimal remain_volume { get; set; }//Decimal(18,3) 剩余量
        public decimal curr_price { get; set; }// Decimal(18,3) 当前价格
        public int meter_state { get; set; }//Int 表状态
        public string meter_stat_emsg { get; set; }// nvarchar(max) 表状态解析信息
        public int rssi { get; set; }// Int 信号强度
        public decimal battery_voltage { get; set; }// Decimal(18,3) 电池电压
        public int battery_level { get; set; }// Int 电池电量
        public string ext_data { get; set; }//JSON 其他数据
    }

    public class MeterData_ExtModel
    {
        //rtu 状态值
        public int? rtu_state { get; set; } = 0;
        //rtu 状态信息
        public string rtu_state_msg { get; set; } = "";
        //表底数
        public decimal? base_volume { get; set; } = 0;
        //累购量
        public decimal? total_buy_value { get; set; } = 0;
        //表计状态数据:
        //开户标志,true-已开户、false-未开户
        public bool? open_state { get; set; } = false;
        //阀门状态,true-开阀、false-关阀
        public bool? valve_open { get; set; } = false;
        //低电等级，0-正常，1-一级低电，2-二级低电
        public int? power_level { get; set; } = 0;
        //远程关阀,无线阀控，true-有、false-无
        public bool? remote_valve_off { get; set; } = false;
        //拆表关阀，true-有、false-无
        public bool? apart_valve_off { get; set; } = false;
        //大流量关阀，true-有、false-无
        public bool? max_flow_valve_off { get; set; } = false;
        //小流量关阀，true-有、false-无
        public bool? min_flow_valve_off { get; set; } = false;
        //死表关阀，true-有、false-无
        public bool? dead_valve_off { get; set; } = false;
        //磁攻击，true-有、false-无
        public bool? magnetic_attack { get; set; } = false;
        //外电情况，true-有、false-无
        public bool? ext_power { get; set; } = false;
        //表计费类型，0-阶梯费率 1-计量表
        public int? calc_type { get; set; } = 0;
        //脉冲故障,干黄故障，true-有、false-无
        public bool? pulse_fault { get; set; } = false;
        //电池断电,扣电，true-有、false-无
        public bool? battery_cut { get; set; } = false;
        //强制开阀，true-有、false-无
        public bool? force_valve_on { get; set; } = false;
        //RTU 状态数据
        //门禁状态（RTU），true-门开、false-门关
        public bool? rtu_door_open { get; set; } = false;
        //市电状态（RTU），true-有、false-无
        public bool? rtu_power { get; set; } = false;
        //围栏异常报警（RTU），true-有、false-无
        public bool? rtu_fence_alarm { get; set; } = false;
        //振动报警（RTU），true-有、false-无
        public bool? rtu_vibrate_alarm { get; set; } = false;
    }

    public class MeterDataUpModel
    {
        public string transaction { get; set; }// String Y   业务流水号，可采用UUID生成        body    List Y   数据上传实体
        public List<meterReadingDetails> body { get; set; }// Y 抄表明细数据
    }
    public class meterReadingDetails
    {
        public string sequence { get; set; }//String Y   业务序列
        public string domainId { get; set; }// String N   公司编码（通过公司查询获取）
        public string orgId { get; set; }//String  N 部门编码（通过部门查询获取）
        public string conMeterCode { get; set; }//String  Y 表通讯号
        public string uniqueDeviceIdentifier { get; set; }//String  Y 设备唯一标示符(表具注册时，通过回调方法返回的值)
        public string meterFactoryCode { get; set; }//String  Y 生产厂家编码
        public double? readNum { get; set; }//double N   读数
        public int readStatus { get; set; }//Integer Y   抄表状态0：未抄表1：已抄2：表具无应答
        public DateTime readTime { get; set; }//Date Y   抄表时间
        public int? valveStatus { get; set; }//Integer N   阀门状态
        public int? dryBatStatus { get; set; }//Integer N   干电池状态0：正常1：欠压2：掉电
        public double? dryBatV { get; set; }//double N   干电池电压
        public int? lithBatStatus { get; set; }//Integer N   锂电池状态0：正常1：欠压2：掉电
        public double? lithBatV { get; set; }//double N   锂电池电压
        public int? dReadStatus { get; set; }//Integer N   直读状态0：正常1：异常
        public int? clockStatus { get; set; }//Integer N   时钟状态0：正常1：异常
        public int? flowStatus { get; set; }//Integer N   流量状态0：正常1：异常
        public int? attackStatus { get; set; }//Integer N   磁攻击状态0：正常1：异常
        public int? signalQuality { get; set; }//Integer N   接收信号质量
        public double? pressure { get; set; }//double N   压力
        public double? workFlow { get; set; }//double N   工况流量
        public double? standardFlow { get; set; }// double N   标况流量
        public double? workTotalFlow { get; set; }// double N   工况累计流量
        public double? standarTotaldFlow { get; set; }//double N   标况累计流量
        public double? temperature { get; set; }//double N   温度
        public int? readMode { get; set; } = 1;//Integer Y 上报方式1: 主动上报(说明：如扩频表具、NB表具主动上报数据的方式)2: 唤醒抄表[扩频] (说明：集中器定时唤醒抄表、抄表命令唤醒抄表等)3：手持机抄表[扩频] (说明：扩频表通过手持机抄取数据的方式)
        public string? deviceCode { get; set; }//String  N 设备编码
        public List<WarnInfo> warnInfos { get; set; }//     N 告警数据
    }
    public class WarnInfo
    {
        public int warnCode { get; set; }//Integer Y   告警编码（参考字典表）
        public string warnDesc { get; set; }//String  Y 告警描述

    }

    public class RtuDataUpModel
    {
        public string transaction { get; set; }//String  Y 业务流水号，可采用UUID生成
        public List<RtuReadingDetails> body { get; set; }//List Y   数据上传实体
    }
    public class RtuReadingDetails
    {
        public string sequence { get; set; }//String  Y 业务序列
        public string domainId { get; set; }//String  Y 公司编码（通过公司查询获取）
        public string orgId { get; set; }//String  N 部门编码（通过部门查询获取）
        public string uniqueDeviceIdentifier { get; set; }//String  Y 设备唯一标示符(表具注册时，通过回调方法返回的值)；如果是分体式设备,为上级设备唯一标识符
        public string deviceCode { get; set; }//String N   设备(采集器、控制器)编码;
        public string deviceType { get; set; }//String  Y 设备类型（参考字典表）
        public int? childChannelNumber { get; set; }//Integer N 子机通道号（设备类型为物联网采集器，必填）
        public string meterFactoryCode { get; set; }//String  Y 生产厂家编码
        public DateTime readTime { get; set; }//Date    Y 抄表时间
        public int? clockStatus { get; set; }//Integer N 时钟状态0：正常1：异常
        public int? flowStatus { get; set; }//Integer N   流量状态0：正常1：异常
        public int? pressureStatus { get; set; }//Integer N   压力状态0：正常1：异常
        public int? temperatureStatus { get; set; }//Integer N   温度状态0：正常1：异常
        public int? attackStatus { get; set; }//Integer N   磁攻击状态0：正常1：异常
        public int? pulseSensorStatus { get; set; }//Integer N   脉冲状态0：正常1：异常
        public int? signalQuality { get; set; }//Integer N   接收信号质量
        public int valveStatus { get; set; }//Integer Y   阀门状态（参考字典表）
        public double standardNum { get; set; }//double Y   累计气量(标况)
        public double workNum { get; set; }//double Y   累计气量(工况)
        public double? instantStandardNum { get; set; }//double N   瞬时流量(标况)
        public double? instantWorkNum { get; set; }//double N   瞬时流量(工况)
        public double? pressure { get; set; }//double N   压力
        public double? temperature { get; set; }//double N   温度
        public double? terminalVoltage { get; set; }//double N   终端电源电压
        public string? terminalVoltagePercentage { get; set; }//Integer N   终端电源电压百分比
        public double? remoteVoltage { get; set; }//double N   远传电池电压
        public int? remoteVoltagePercentage { get; set; }//Integer N   远传电池电压百分比
        public double? valveVoltage { get; set; }//double N   阀门电池电压
        public int? valveVoltagePercentage { get; set; }//Integer N   阀门电池电压百分比
        public double? cumulativePurchase { get; set; }//Double N   累购;计费方式为中心计费默认为0
        public double? surplus { get; set; }//Double N   剩余金额;计费方式为中心计费默认为0
        public double? price { get; set; }//Double N   单价;计费方式为中心计费默认为0
        public int? payCount { get; set; }//Integer N   充值次数;计费方式为中心计费默认为0
        public string meteringType { get; set; } = "02";//String Y   计量类别（参考字典表）；计费方式为中心计费默认为金额模式
        public string calcTypeCode { get; set; } = "1";//String Y   计费方式（参考字典表）
        public int? readMode { get; set; }//Integer N 采集方式(默认为1)1: 设备自动采集
        public List<RtuWarnInfoModel>? warnInfos { get; set; }//List N   告警数据
    }

    public class RtuWarnInfoModel
    {
        public int? warnCode { get; set; }//Integer Y 告警编码（参考字典表）
        public string? warnDesc { get; set; }//String Y 告警描述
        public DateTime? warnTime { get; set; }//Date N 告警时间
    }

    public class ReqRtuRemainMoneyModel
    {
        public string? appId { get; set; }
        public string? cacheCmdCode { get; set; }
        public string? sequence { get; set; }//String Y 业务序列
        public string? domainId { get; set; }//String Y 公司id
        public string? uniqueDeviceIdentifier { get; set; }// String Y 设备唯一标示符(表具注册时，通过回调方法返回的值)
        public string? commandTimeliness { get; set; }// String Y 命令时效性:WINDOW: 窗口命令REALTIME: 唤醒命令
        public string? meterCommandCode { get; set; }//   String Y   余额同步：SYNC_BALANCE
        public RtuCmdParamModel? cmdParam { get; set; }//  Object Y   余额同步参数
        public string? deviceType { get; set; }
    }

    public class RtuCmdParamModel
    {
        public string? valveControlState { get; set; }// String  Y 阀门控制状态DEFAULT：默认不控阀OPEN：   开阀CLOSE：  关阀ALARM_CLOSE：  预警关阀
        public double? settlementBalance { get; set; }//  Double Y   结算余额，单位元，保留2位小数
        public double? settlementNum { get; set; }//  Double Y   结算读数
        public Int64? settlementTime { get; set; }// Date Y   结算时间
        public double? unitPrice { get; set; }// Double Y   单价，单位元，保留2位小数
        public double? recentRechargeAmount { get; set; }//  Double Y   最近一次的交费金额 ，单位元，保留2位小数
        public Int64? recentPaymentTime { get; set; }/// Date Y   最近一次的交费日期
        public int? calcSource { get; set; }
        public string? lastTimeUnitPrice { get; set; }//
        public string? lastTimeSurplus { get; set; }//
        public Int64? lastTimeSettlementDate { get; set; }//
    }

    public class SendAlarmModel
    {
        public string sequence { get; set; }//String  Y 业务序列
        public string domainId { get; set; }//String  Y 公司编码（通过公司查询获取）
        public string deviceType { get; set; }//String  Y 设备类型（参考字典表）
        public string protocolTypeCode { get; set; } = "99999";//String  Y 协议类型（固定值99999）
        public string uniqueDeviceIdentifier { get; set; }//String  Y 设备唯一标示符(表具注册时，通过回调方法返回的值)；如果是控制器,为控制器设备唯一标识符
        public string deviceCode { get; set; }// String N   设备(采集器、控制器)编码;
        public List<AlarmInfo> warnInfos { get; set; }// Y 报警信息对象的集合
    }
    public class AlarmInfo
    {
        public int? warnCode { get; set; }//Integer Y 告警编码（参考字典表）
        public string? warnDesc { get; set; }//String Y 告警描述
        public DateTime? warnTime { get; set; }//Date N 告警时间
        public bool closeValve { get; set; } = false;
    }
}
